package com.singleton;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Locale;
import java.util.ResourceBundle;
import com.mchange.v2.c3p0.ComboPooledDataSource;

//枚举类型不允许被继承，同样是线程安全的且只能被实例化一次，但是枚举类型不能够懒加载，对SingleEnum主动使用，比如调用其中的静态方法则DATASOURCE会立即得到实例化。
/**枚举可解决线程安全问题
 * 了解JVM的类加载机制的朋友应该对这部分比较清楚。static类型的属性会在类被加载之后被初始化，我们在深度分析Java的ClassLoader机制（源码级别）中介绍过，当一个Java类第一次被真正使用到的时候
 * 静态资源被初始化、Java类的加载和初始化过程都是线程安全的（因为虚拟机在加载枚举的类的时候，会使用ClassLoader的loadClass方法，而这个方法使用同步代码块保证了线程安全）。所以，创建一个enum类型是线程安全的。
也就是说，我们定义的一个枚举，在第一次被真正用到的时候，会被虚拟机加载并初始化，而这个初始化过程是线程安全的。而我们知道，解决单例的并发问题，主要解决的就是初始化过程中的线程安全问题。
所以，由于枚举的以上特性，枚举实现的单例是天生线程安全的。

枚举可避免反序列化破坏单例
前面我们提到过，使用“双重校验锁”实现的单例其实是存在一定问题的，就是这种单例有可能被序列化锁破坏。
对于序列化这件事情，为什么枚举又有先天的优势了呢？答案可以在Java Object Serialization Specification 中找到答案。其中专门对枚举的序列化做了如下规定：
大概意思就是：在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中，反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。同时，编译器是不允许任何对这种序列化机制的定制的，因此禁用了writeObject、readObject等方法。
普通的Java类的反序列化过程中，会通过反射调用类的默认构造函数来初始化对象。所以，即使单例中构造函数是私有的，也会被反射给破坏掉。但是在newInstance方法中，判断了如果是enum就抛出异常
 *
 */
public enum SingleEnum {

	DATASOURCE;
    private ComboPooledDataSource cpds = null;

    private SingleEnum() {
        try {
            ResourceBundle rs = ResourceBundle.getBundle("jdbc", new Locale("zh","CN"));
            cpds = new ComboPooledDataSource();
            cpds = new ComboPooledDataSource();
            cpds.setDriverClass(rs.getString("driverClass"));
            cpds.setJdbcUrl(rs.getString("jdbcUrl"));
            cpds.setUser(rs.getString("user"));
            cpds.setPassword(rs.getString("password"));
            cpds.setMaxPoolSize(Integer.parseInt(rs.getString("maxPoolSize")));
            cpds.setMinPoolSize(Integer.parseInt(rs.getString("minPoolSize")));
            System.out.println("-----调用了构造方法------");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static SingleEnum getInstance(){
		return DATASOURCE;
	}

    public Connection getConnection() {
        try {
            return cpds.getConnection();
        } catch (SQLException e) {
            return null;
        }
    }

    public static void main(String[] args) {
    	SingleEnum.DATASOURCE.getConnection();
	}

}
